iT邦幫忙

2022 iThome 鐵人賽

DAY 30
0
自我挑戰組

老菜雞挑戰30天學爆Unity&C#會成功嗎?...系列 第 30

【Day30】老菜雞學下樓梯遊戲之挑戰成功-回顧及Review Unity重點

  • 分享至 

  • xImage
  •  

前言

遊戲在昨天已經告一段落了,那我們在最後一天來Review這30天來主要學到哪些東西吧!


Unity C#

  • 物件移動:transform.Translate(x軸上的位移量,y軸上的位移量,z軸上的位移量);
  • 取得使用者輸入去控制物件:Input.GetKey (KeyCode key);
    KeyCode會直接對應到鍵盤上的按鍵。可以參考KeyCode
  • 判斷碰撞物件-OnCollisionEnter2D,搭配tag去判斷撞到哪個物件-GameObject.tag
  • 判斷經過物件- OnTriggerEnter2D,搭配Collider.isTrigger
  • 隨機產生:Random.Range(最小值,最大值)
  • 自動生成物件:Instantiate(被生成的物件, 物件位置)
  • 刪除物件:Destroy(被刪除的物件)
  • 抓取物件的屬性:GetComponent<物件名稱>().變數/函式
  • 物件接觸點:物件.contacts[0].point
  • 物件法向量:物件.contacts[0].normal
  • 物件的啟用與停用:gameObject.SetActive(true或false)
  • 將Bool值用於觸發動畫:GetComponent().SetBool("參數名稱",true或者false);
  • 播放音效:gameObject. GetComponent().Play();
  • 調整遊戲倍速:Time.timeScale
  • 場景重載:SceneManager.LoadScene("場景名稱");

Unity Component

Sprite Renderer

  • 匯入圖片:直接拖曳圖片拉到Sprite
  • 物件的水平或垂直翻轉:設定Flip

Rigidbody

  • 想要讓物件像實體一樣:物件上新增component—Rigidbody
  • 取消物件旋轉:Constraints的Z打勾。

Collider

  • 讓物件能站在另一個物件上面(碰撞範圍):物件上新增component—Collider
  • 快速調整符合圖片的碰撞範圍呢:在Box Collider 2D按滑鼠右鍵點Reset

Animator

  • 物件新增動畫功能:物件上新增component—Animator

Audio Source

  • 物件新增音效:物件上新增component— Audio Source

Prefab

  • 製作Prefab:物件直接從Hierachy視窗上拖曳到Project視窗
  • 要改變其中一個屬性時,要記得Overrides

Unity UI

  • 文字(Text)
  • 圖像(Image)
  • 按鈕(Button)

Unity Animation

  • Animator Controller:可製作動畫加入到Controller
  • Animator:會顯示這個物件的動畫是如何播放的
  • Animation Transition讓動畫之間可以做切換
  • Animation Parameters:可以讓程式碼去控制動畫狀態流程
  • Animation Layers:管理物件多層的動畫

遊戲完整程式碼

Player.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;//要使用TextMeshPro資料型態時需引入TMPro
using UnityEngine.SceneManagement;

public class Player : MonoBehaviour
{
    [SerializeField] float speed = 5f;
    GameObject currentFloor;
    [SerializeField]  int Hp;
    [SerializeField]  GameObject HpBar;
    [SerializeField]  TextMeshProUGUI scoreText;
    int score;//紀錄現在到第幾level
    float scoreTime;//紀錄現在過了多久時間
    AudioSource deathSound;
    [SerializeField]GameObject replayButton;

    void Start()
    {
        Hp = 10;
        score = 0;
        scoreTime = 0;
        deathSound = GetComponent<AudioSource>();
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetKey(KeyCode.D)) {
            transform.Translate(speed*Time.deltaTime,0,0);
            GetComponent<SpriteRenderer>().flipX = false;
            GetComponent<Animator>().SetBool("run",true);
        }
        else if(Input.GetKey(KeyCode.A)) {
            transform.Translate(-speed*Time.deltaTime,0,0);
            GetComponent<SpriteRenderer>().flipX = true;
            GetComponent<Animator>().SetBool("run",true);
        }
        else
        {
             GetComponent<Animator>().SetBool("run",false);
        }
        UpdateScore();
    }

     void OnCollisionEnter2D(Collision2D other)  //other是指碰撞到的東西 
    { 
    if(other.gameObject.tag == "Normal") 
    {
        if(other.contacts[0].normal == new Vector2(0f,1f)) 
        {
             Debug.Log("撞到Normal"); 
            currentFloor = other.gameObject;
            ModifyHp(1);
            other.gameObject. GetComponent<AudioSource>().Play();
        }
       
    }	 
    else if(other.gameObject.tag == "Nails") 

    { 
        if(other.contacts[0].normal == new Vector2(0f,1f)) 
        {
             Debug.Log("撞到Nails"); 
             currentFloor = other.gameObject;
             ModifyHp(-3);
             GetComponent<Animator>().SetTrigger("hurt");
             other.gameObject. GetComponent<AudioSource>().Play();
        }
        
    } 
      else if(other.gameObject.tag == "Ceiling") 

    { 
        Debug.Log("撞到天花板"); 
        currentFloor.GetComponent<BoxCollider2D>().enabled = false;
        ModifyHp(-3);
          GetComponent<Animator>().SetTrigger("hurt");
          other.gameObject.GetComponent<AudioSource>().Play();
    } 

    }

     void OnTriggerEnter2D(Collider2D other) {
        if(other.gameObject.tag == "DeathLine") 
    {
        Debug.Log("你輸了!"); 
        deathSound.Play();
        Time.timeScale = 0f;
        replayButton.SetActive(true);
    }
    }

    void ModifyHp(int num)
    {
        Hp += num;
        if(Hp > 10)
        {
            Hp = 10;
        }
        else if(Hp <= 0)
        {
            Hp = 0;
            deathSound.Play();
            Time.timeScale = 0f;
            replayButton.SetActive(true);
        }
        UpdateHpBar();
    }

    void UpdateHpBar()
    {
        for(int i=0;i<HpBar.transform.childCount;i++)
        {
            if(Hp>i)
            {
                HpBar.transform.GetChild(i).gameObject.SetActive(true);
            }
            else
            {
                HpBar.transform.GetChild(i).gameObject.SetActive(false);
            }
        }
    }

    void UpdateScore()
    {
        scoreTime +=Time.deltaTime;//用Time.deltaTime來計算時間,因為它是每次Update方法被呼叫到的間隔時間
        if(scoreTime>2f)  //只要scoreTime超過2秒,就把分數+1更新到文字上,並歸零時間
        {
            score++;
            scoreTime = 0f;
            scoreText.text = "Level" + score.ToString();
        }
    }

    public void Replay()
    {
        Time.timeScale = 1f;
        SceneManager.LoadScene("SampleScene");
    }
 }

Floor.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Floor : MonoBehaviour
{
    [SerializeField] float moveSpeed = 2f; 
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        transform.Translate(0,moveSpeed*Time.deltaTime,0); 
        if(transform.position.y > 6f)
        {
             Destroy(gameObject); 
             transform.parent.GetComponent<FloorManager>().SpawnFloor();
        }
}
}

FloorManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FloorManager : MonoBehaviour
{
   [SerializeField] GameObject[] FloorPrefabs; 

    public void SpawnFloor()
    { 
        int r = Random.Range(0,FloorPrefabs.Length);
       GameObject floor = Instantiate(FloorPrefabs[r],transform); 
       floor.transform.position = new Vector3(Random.Range(-3.8f,3.8f),-6f,0f);
    } 
    
}


心得

終於要從今年的鐵人賽畢業啦~雖然30天說長不長說短不短,但寫IT已經變成我這過去30天的習慣,每天有空先做的事情就是寫文章,也從這裡學習到很多Unity的技術/images/emoticon/emoticon07.gif
最後再次由衷感謝影片教程的作者,解說得很好、很用心,大家也一定要去觀看這個影片喔!

  • 參考網址:https://www.youtube.com/watch?v=nPW6tKeapsM&ab_channel=GrandmaCan-%E6%88%91%E9%98%BF%E5%AC%A4%E9%83%BD%E6%9C%83

  • 音效、圖片 : 遊戲素材
    (素材由安德斯提供,感謝大大/images/emoticon/emoticon41.gif)


上一篇
【Day29】老菜雞學下樓梯遊戲之大功告成-Unity 匯出遊戲
系列文
老菜雞挑戰30天學爆Unity&C#會成功嗎?...30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言